package com.cskaoyan.wordmemorize.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cskaoyan.wordmemorize.aop_whh.annotation.OperateLog;
import com.cskaoyan.wordmemorize.common.constant.ResultCodeEnum;
import com.cskaoyan.wordmemorize.common.exception.BusinessException;
import com.cskaoyan.wordmemorize.common.exception.ExcelParseException;
import com.cskaoyan.wordmemorize.converter.TopicConverter;
import com.cskaoyan.wordmemorize.converter.VocConverter;
import com.cskaoyan.wordmemorize.dao.entity.ReviewSubTopicDO;
import com.cskaoyan.wordmemorize.dao.entity.ReviewTopicDO;
import com.cskaoyan.wordmemorize.dao.entity.TopicOptionDO;
import com.cskaoyan.wordmemorize.dao.entity.VocDO;
import com.cskaoyan.wordmemorize.dao.mapper.ReviewSubTopicMapper;
import com.cskaoyan.wordmemorize.dao.mapper.ReviewTopicMapper;
import com.cskaoyan.wordmemorize.dao.mapper.TopicOptionsMapper;
import com.cskaoyan.wordmemorize.dao.mapper.VocMapper;
import com.cskaoyan.wordmemorize.dto.admin.*;
import com.cskaoyan.wordmemorize.excel.FillWordExcelSaver;
import com.cskaoyan.wordmemorize.excel.FillWordExcelValidator;
import com.cskaoyan.wordmemorize.excel.SingleChoiceExcelSaver;
import com.cskaoyan.wordmemorize.excel.SingleChoiceExcelValidator;
import com.cskaoyan.wordmemorize.request.ReviewSubTopicCommand;
import com.cskaoyan.wordmemorize.request.TopicCommand;
import com.cskaoyan.wordmemorize.request.TopicOptionCommand;
import com.cskaoyan.wordmemorize.request.VocPageRequest;
import com.cskaoyan.wordmemorize.service.TopicService;
import jakarta.annotation.Resource;
import org.glassfish.jaxb.core.v2.TODO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

@Service

public class TopicServiceImpl extends ServiceImpl<ReviewTopicMapper, ReviewTopicDO> implements TopicService {

    @Autowired
    ReviewTopicMapper reviewTopicMapper;

    @Autowired
    TopicConverter topicConverter;

    @Autowired
    VocMapper vocMapper;
    @Autowired
    TopicOptionsMapper topicOptionsMapper;

    @Autowired
    ReviewSubTopicMapper reviewSubTopicMapper;

    @Autowired
    VocConverter vocConverter;
    @Resource
    SingleChoiceExcelValidator singleChoiceExcelValidator;
    @Resource
    FillWordExcelValidator fillWordExcelValidator;
    @Resource
    SingleChoiceExcelSaver singleChoiceExcelSaver;
    @Resource
    FillWordExcelSaver fillWordExcelSaver;
    @Resource
    ResourceLoader resourceLoader;
    @Value("${excel.template.topic.choice}")
    private String singleChoiceTemplatePath;

    @Value("${excel.template.topic.fill}")
    private String fillWordTemplatePath;
    @Override
    public VocDTO checkWord(String word) {
        if (word == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        LambdaQueryWrapper<VocDO> wrapper = new LambdaQueryWrapper<VocDO>()
                .eq(true, VocDO::getContent, word);

        VocDO vocDO = vocMapper.selectOne(wrapper);
        return vocConverter.vocDO2DTO(vocDO);
    }

    // 分页获取单选题列表(物料管理-题目管理)
    @Override
    public PageDTO<ReviewTopicDTO> getSingleChoicePage(VocPageRequest vocPageRequest) {
        if (vocPageRequest == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        Integer pageNum = vocPageRequest.getPageNum();
        Integer count = vocPageRequest.getCount();
        String bookId = vocPageRequest.getBookId();
        Integer topicType = vocPageRequest.getTopicType();
        String chapterId = vocPageRequest.getChapterId();
        String keyword = vocPageRequest.getKeyword();

        Page<ReviewTopicDO> reviewTopicDOPage = new Page<>(pageNum, count);
        LambdaQueryWrapper<ReviewTopicDO> wrapper = new LambdaQueryWrapper<ReviewTopicDO>()
                .eq(topicType != null, ReviewTopicDO::getTopicType, topicType)
                .like(keyword != null, ReviewTopicDO::getVocabulary, keyword);
        Page<ReviewTopicDO> page = reviewTopicMapper.selectPage(reviewTopicDOPage, wrapper);
        List<ReviewTopicDO> records = page.getRecords();
        long total = page.getTotal();
        return topicConverter.topicDOPage2PageDTO(records, total);

    }

    // 分页获取选词填空题列表(物料管理-题目管理)
    @Override
    public PageDTO<ReviewTopicDTO> getFillWordPage(VocPageRequest vocPageRequest) {
        if (vocPageRequest == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        Integer pageNum = vocPageRequest.getPageNum();
        Integer count = vocPageRequest.getCount();
        String bookId = vocPageRequest.getBookId();
        Integer topicType = vocPageRequest.getTopicType();
        String chapterId = vocPageRequest.getChapterId();
        String keyword = vocPageRequest.getKeyword();

        Page<ReviewTopicDO> reviewTopicDOPage = new Page<>(pageNum, count);
        LambdaQueryWrapper<ReviewTopicDO> wrapper = new LambdaQueryWrapper<ReviewTopicDO>()
                .eq(topicType != null, ReviewTopicDO::getTopicType, topicType)
                .like(keyword != null, ReviewTopicDO::getVocabulary, keyword);
        Page<ReviewTopicDO> page = reviewTopicMapper.selectPage(reviewTopicDOPage, wrapper);
        List<ReviewTopicDO> records = page.getRecords();
        long total = page.getTotal();
        return topicConverter.topicDOPage2PageDTO(records, total);
    }


    // 添加题目(物料管理-题目管理)
    @OperateLog(dateType = "题目", operateType = 0)
    @Override
    @Transactional
    public void addTopic(TopicCommand command) {
        if (command == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        //先将其转化为topicDO
        ReviewTopicDO topicDO = topicConverter.command2TopicDO(command);
        //先根据subTopics存在与否判断题目类型
        if (command.getTopicType() == 1) {
            //当是单选题时，先在review_topic中插入数据，主要是vocabulary topic voc_id
            String vocabulary = topicDO.getVocabulary();
            //根据单词查询其所在的voc_id并进行设置
            LambdaQueryWrapper<VocDO> vocWrapper = new LambdaQueryWrapper<VocDO>()
                    .eq(vocabulary != null, VocDO::getContent, vocabulary);
            VocDO vocDO = vocMapper.selectOne(vocWrapper);
            Long vocId = vocDO.getId();
//            Long vocId = vocMapper.getIdByContent(vocabulary);
            topicDO.setVocId(vocId);
            //先设置vocId后再进行设置
            save(topicDO);
            //再到topic_options表中，插入数据，主要是tid, item, is_answer, option_number
            //根据command中的Options
            List<TopicOptionCommand> options = command.getOptions();
            for (TopicOptionCommand option : options) {
                TopicOptionDO optionDO = topicConverter.reviewSubTopicCommand2TopicDO(option);
                //设置其tid
                optionDO.setTid(topicDO.getId());
                topicOptionsMapper.insert(optionDO);
            }

        } else if (command.getTopicType() == 2) {
            //当类型为2时，先在review_topic中插入整体数据，但topic列并没有值

            save(topicDO);
                //获取到其id的值，为其他表的tid
            Long tId = topicDO.getId();
            //再在topic_options中插入干扰数据
            //遍历再加入，可能有多个
            List<TopicOptionCommand> options = command.getOptions();

            if (options != null) {
                for (TopicOptionCommand option : options) {
                    TopicOptionDO optionDO = topicConverter.reviewSubTopicCommand2TopicDO(option);
                    optionDO.setTid(tId);
                    topicOptionsMapper.insert(optionDO);
                }
            }

            //再于review_sub_topic中插入每一个选项和对应单词
            List<ReviewSubTopicCommand> subTopics = command.getSubTopics();
            List<ReviewSubTopicDO> reviewSubTopicDOS = topicConverter.commands2ReviewSubTopicDOs(subTopics);
            //再定义指定格式的topic与vocabulary，更新到review_topic中
            //因为vocabulary在请求中有了，不用再改变格式
            String topic = "";
            for (ReviewSubTopicDO reviewSubTopicDO : reviewSubTopicDOS) {
                //因为tId的原因，不能批量存入
                reviewSubTopicDO.setTid(tId);
                reviewSubTopicMapper.insert(reviewSubTopicDO);
                topic += reviewSubTopicDO.getTopicItem() + "\n";
            }
            topicDO.setTopic(topic);
            saveOrUpdate(topicDO);
        }else {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }


//
//        //在review_sub_topic中设置topic的字段
//        String topic = null;
//        List<ReviewSubTopicCommand> subTopics = command.getSubTopics();
//        for (ReviewSubTopicCommand subTopic : subTopics) {
//            String topicItem = subTopic.getTopicItem();
//            topic = topicItem + System.lineSeparator();
//
//        }
//        topicDO.setTopic(topic);
//        //将数据插入到review_topic中
//        save(topicDO);
//        Long subTid = topicDO.getId();
//
//        List<ReviewSubTopicDO> reviewSubTopicDOS = topicConverter.commands2ReviewSubTopicDOs(subTopics);
//        reviewSubTopicMapper.insert(reviewSubTopicDOS);
//
//
//        Long tId = topicDO.getId();
//
//        //获取options中的数据并插入到表topic_options中
//        List<TopicOptionDO> options = topicDO.getOptions();
//        for (int i = 0; i < options.size(); i++) {
//            options.get(i).setTid(tId);
//        }
//        topicOptionsMapper.insert(options);
    }

    // 获取题目(物料管理-题目管理)
    @Override
    public ReviewTopicDTO getTopic(Long topicId) {
        //这里出现了递归调用
//        ReviewTopicDTO reviewTopicDTO = getTopic(topicId);
        if (topicId == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        ReviewTopicDO reviewTopicDO = getById(topicId);
        Long tId = reviewTopicDO.getId();
        HashMap<String, Object> map = new HashMap<>();
        map.put("tid", tId);
        List<TopicOptionDO> topicOptionDOS = topicOptionsMapper.selectByMap(map);
        ReviewTopicDTO reviewTopicDTO = topicConverter.reviewTopicDO2DTO(reviewTopicDO);
        reviewTopicDTO.setOptions(topicConverter.topicOptionDOs2DTOs(topicOptionDOS));
        if (reviewTopicDO.getTopicType() == 1) {
            return reviewTopicDTO;

        }
        //当类型为2时，还需要设置sutTopics的字段
        List<ReviewSubTopicDO> reviewSubTopicDOS = reviewSubTopicMapper.selectByMap(map);

        List<ReviewSubTopicDTO> reviewSubTopicDTOS = topicConverter.reviewSubTopicDOs2DTOs(reviewSubTopicDOS);

        reviewTopicDTO.setSubTopics(reviewSubTopicDTOS);
        return reviewTopicDTO;


       /*
        Integer topicType = reviewTopicDTO.getTopicType();
        HashMap<String, Object> map = new HashMap<>();
        map.put("tid", topicId);
        //判断是单选题的情况
        //无需要判断，因为值是1或2都有这个情况
        List<TopicOptionDO> topicOptionDOS = topicOptionsMapper.selectByMap(map);
        reviewTopicDTO.setOptions(topicConverter.topicOptionDOs2DTOs(topicOptionDOS));

        //判断是多选题的情况
        if (topicType == 2) {
            //options和subTopics都要有值
            List<ReviewSubTopicDO> reviewSubTopicDOS = reviewSubTopicMapper.selectByMap(map);
            reviewTopicDTO.setSubTopics(topicConverter.reviewSubTopicDOs2DTOs(reviewSubTopicDOS));
        }


        return reviewTopicDTO;*/
    }

    // 更新题目(物料管理-题目管理)
    @Override
    public void updateTopic(TopicCommand command) {
        if (command == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        //先判断类型，再进行修改
        ReviewTopicDO reviewTopicDO = topicConverter.command2TopicDO(command);
        Long tId = reviewTopicDO.getId();
        if (reviewTopicDO.getTopicType() == 1) {
            //当为单选题时，可能：topic vocabulary vocId 均会发生变化，此时进行更新，但其id不变
                //已经自动封装好，直接更新
            saveOrUpdate(reviewTopicDO);
            //新增的option直接添加，修改的进行删除，需要设置tId
            List<TopicOptionDO> options = reviewTopicDO.getOptions();
            for (TopicOptionDO option : options) {
                option.setTid(tId);
                topicOptionsMapper.insertOrUpdate(option);
            }
            //option选项中的code会发生变化，根据其id进行变更，就行，但其tId是不变滴
        } else if (reviewTopicDO.getTopicType() == 2) {
            //1、在review_topic中更新数据，但是topic字段先不更新

            //2、在topic_options中更新排除项的信息
            List<TopicOptionDO> options = reviewTopicDO.getOptions();
            if (options != null) {
                for (TopicOptionDO option : options) {
                    option.setTid(tId);
                    topicOptionsMapper.insert(option);
                }
            }
            //3、在review_sub_topic中更新题目的信息
            List<ReviewSubTopicCommand> subTopics = command.getSubTopics();
            List<ReviewSubTopicDO> reviewSubTopicDOS = topicConverter.commands2ReviewSubTopicDOs(subTopics);
            String topic = "";
            for (ReviewSubTopicDO reviewSubTopicDO : reviewSubTopicDOS) {
                topic += reviewSubTopicDO.getTopicItem() + System.lineSeparator();
                reviewSubTopicDO.setTid(tId);
                reviewSubTopicMapper.insertOrUpdate(reviewSubTopicDO);
            }
            //最后更新review_topic
            reviewTopicDO.setTopic(topic);
            saveOrUpdate(reviewTopicDO);

        }else {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }

    }

    // 删除题目(物料管理-题目管理)
    @Transactional
    @Override
    //这里直接返回了null, 因为找不到对应的返回对象。
    public DeleteTopicOperateDTO deleteTopic(Long topicId, Integer topicType) {
        if (topicId == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        //根据topicId删除主表，再根据topicType的不同到不同的表进行删除
        //删除主表
        removeById(topicId);

        //为1时，在topic_option中进行删除
        HashMap<String, Object> map = new HashMap<>();
        map.put("tid", topicId);
        if (topicId == 1) {
            topicOptionsMapper.deleteByMap(map);
        }
        List<TopicOptionDO> topicOptionDOS = topicOptionsMapper.selectByMap(map);
        ReviewTopicDO reviewTopicDO = getById(topicId);

        //等于2时再进行review_sub_topic删除
        //好像是另一个接口
//        if (topicType == 2) {
//            reviewSubTopicMapper.deleteByMap(map);
//        }


        return topicConverter.topicDO2DeleteTopicDTO(reviewTopicDO);

    }

    // 检查excel中的题目(物料管理-题目管理)
    @Override
    public void topicExcelValidate(String type, MultipartFile file) throws IOException {
        // 文件基本检查
        if (file == null || file.isEmpty()) {
            throw new ExcelParseException(ResultCodeEnum.PARAM_ERROR, "Excel文件不能为空");
        }

        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null ||
                !(originalFilename.endsWith(".xlsx") || originalFilename.endsWith(".xls"))) {
            throw new ExcelParseException(ResultCodeEnum.PARAM_ERROR, "请上传Excel文件(.xlsx或.xls)");
        }

        // 校验
        if ("single".equals(type)) {
            singleChoiceExcelValidator.validate(singleChoiceTemplatePath, file.getInputStream());
            return;
        }
        if ("fill".equals(type)) {
            fillWordExcelValidator.validate(fillWordTemplatePath, file.getInputStream());
        }
    }
    // excel添加单选题目(物料管理-题目管理)
    @Override
    public ExcelAddOperateDTO addSinleChoiceExcel(MultipartFile file, Long employeeId) throws IOException {

        Integer count = singleChoiceExcelSaver
                .upload(file, SingleTopicExcelDTO.class, singleTopicExcelDTO -> singleTopicExcelDTO);
        ExcelAddOperateDTO excelAddOperateDTO = new ExcelAddOperateDTO();
        excelAddOperateDTO.setTotalCount(count);
        excelAddOperateDTO.setFileName(file.getOriginalFilename());
        return excelAddOperateDTO;
    }
    // excel添加填空题目(物料管理-题目管理)
    @Override
    public ExcelAddOperateDTO addFillWordExcel(MultipartFile file, Long employeeId) throws IOException {

        Integer count = fillWordExcelSaver
                .upload(file, FillTopicExcelDTO.class, fillTopicExcelDTO -> fillTopicExcelDTO);

        ExcelAddOperateDTO excelAddOperateDTO = new ExcelAddOperateDTO();
        excelAddOperateDTO.setTotalCount(count);
        excelAddOperateDTO.setFileName(file.getOriginalFilename());
        return excelAddOperateDTO;
    }

    // 删除选词填空题的小题(物料管理-题目管理)
    @Override
    public DeleteSubTopicOperateDTO deleteSubTopic(Long id) {
        if (id == null) {
            throw new BusinessException(ResultCodeEnum.FAIL);
        }
        //id为单词的在voc中的id，即voc_id
        //根据voc_id进行删除
        LambdaQueryWrapper<ReviewSubTopicDO> subWrapper = new LambdaQueryWrapper<ReviewSubTopicDO>()
                .eq(true, ReviewSubTopicDO::getVocId, id);
        reviewSubTopicMapper.delete(subWrapper);

        //得到删除单词在review_sub_topic的tid字段得到相同的tid行的vocabulary与topic_item列
        ReviewSubTopicDO reviewSubTopicDO = reviewSubTopicMapper.selectOne(subWrapper);
        Long tid = reviewSubTopicDO.getTid();
        HashMap<String, Object> map = new HashMap<>();
        map.put("tid", tid);
        List<ReviewSubTopicDO> reviewSubTopicDOS = reviewSubTopicMapper.selectByMap(map);
        //如果没有，则删除review_topic表中将id = tid的行
        if (reviewSubTopicDOS == null) {
            reviewTopicMapper.deleteById(tid);
        }
        //有的话，将vocabulary与topic_item进行拼接更新到表review_topic中的vocabulary与topic列
        //定义vocabulary与topic
        String vocabulary = null;
        String topic = null;
        for (ReviewSubTopicDO subTopicDO : reviewSubTopicDOS){
            vocabulary = vocabulary + subTopicDO.getVocabulary() + ",";
            topic = topic + subTopicDO.getTopicItem() + "\n";
        }
        LambdaUpdateWrapper<ReviewTopicDO> reviewWrapper = new LambdaUpdateWrapper<ReviewTopicDO>()
                .set(vocabulary != null, ReviewTopicDO::getVocabulary, vocabulary)
                .set(topic != null, ReviewTopicDO::getTopic, topic);

        reviewTopicMapper.update(reviewWrapper);
        return topicConverter.toDeleteSubTopicDTO(reviewSubTopicDO);
    }

    // 删除选词填空题的干扰项或者删除单选题选项(物料管理-题目管理)
    @Override
    public DeleteTopicOptionOperateDTO deleteTopicOption(Long id) {
        if (id == null) {
            throw  new BusinessException(ResultCodeEnum.FAIL);
        }
        TopicOptionDO topicOptionDO = topicOptionsMapper.selectById(id);
//        String item = topicOptionDO.getItem();
        Long tid = topicOptionDO.getTid();
        ReviewTopicDO reviewTopicDO = getById(tid);
        String topic = reviewTopicDO.getTopic();
        topicOptionsMapper.deleteById(id);

//        removeById(id);
//        ReviewTopicDO reviewTopicDO = getById(id);
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("tid", id);
//        LambdaQueryWrapper<TopicOptionDO> wrapper = new LambdaQueryWrapper<TopicOptionDO>()
//                .eq(true, TopicOptionDO::getTid, id);
//        TopicOptionDO optionDO = topicOptionsMapper.selectOne(wrapper);
        return topicConverter.toDeleteTopicOptionDTO(topicOptionDO, topic);

    }
}
